import omit from 'omit.js'
import BaseMixin from '../../_util/BaseMixin'
import PropTypes from '../../_util/vue-types'
import KeyCode from './KeyCode'
import { getOptionProps } from '../../_util/props-util'
import { cloneElement } from '../../_util/vnode'

function getDefaultActiveKey (props) {
  let activeKey
  const children = props.children
  children.forEach((child) => {
    if (child && !activeKey && !child.disabled) {
      activeKey = child.key
    }
  })
  return activeKey
}

function activeKeyIsValid (props, key) {
  const children = props.children
  const keys = children.map(child => child && child.key)
  return keys.indexOf(key) >= 0
}

export default {
  name: 'Tabs',
  model: {
    prop: 'activeKey',
    event: 'change',
  },
  mixins: [BaseMixin],
  props: {
    destroyInactiveTabPane: PropTypes.bool,
    renderTabBar: PropTypes.func.isRequired,
    renderTabContent: PropTypes.func.isRequired,
    navWrapper: PropTypes.func.def(arg => arg),
    children: PropTypes.any.def([]),
    prefixCls: PropTypes.string.def('ant-tabs'),
    tabBarPosition: PropTypes.string.def('top'),
    activeKey: PropTypes.string,
    defaultActiveKey: PropTypes.string,
    __propsSymbol__: PropTypes.any,
  },
  data () {
    const props = getOptionProps(this)
    let activeKey
    if ('activeKey' in props) {
      activeKey = props.activeKey
    } else if ('defaultActiveKey' in props) {
      activeKey = props.defaultActiveKey
    } else {
      activeKey = getDefaultActiveKey(props)
    }
    return {
      _activeKey: activeKey,
    }
  },
  watch: {
    __propsSymbol__ () {
      const nextProps = getOptionProps(this)
      if ('activeKey' in nextProps) {
        this.setState({
          _activeKey: nextProps.activeKey,
        })
      } else if (!activeKeyIsValid(nextProps, this.$data._activeKey)) {
        // https://github.com/ant-design/ant-design/issues/7093
        this.setState({
          _activeKey: getDefaultActiveKey(nextProps),
        })
      }
    },
  },
  methods: {
    onTabClick (activeKey, e) {
      if (this.tabBar.componentOptions &&
        this.tabBar.componentOptions.listeners &&
        this.tabBar.componentOptions.listeners.tabClick) {
        this.tabBar.componentOptions.listeners.tabClick(activeKey, e)
      }
      this.setActiveKey(activeKey)
    },

    onNavKeyDown (e) {
      const eventKeyCode = e.keyCode
      if (eventKeyCode === KeyCode.RIGHT || eventKeyCode === KeyCode.DOWN) {
        e.preventDefault()
        const nextKey = this.getNextActiveKey(true)
        this.onTabClick(nextKey)
      } else if (eventKeyCode === KeyCode.LEFT || eventKeyCode === KeyCode.UP) {
        e.preventDefault()
        const previousKey = this.getNextActiveKey(false)
        this.onTabClick(previousKey)
      }
    },

    setActiveKey (activeKey) {
      if (this.$data._activeKey !== activeKey) {
        const props = getOptionProps(this)
        if (!('activeKey' in props)) {
          this.setState({
            _activeKey: activeKey,
          })
        }
        this.__emit('change', activeKey)
      }
    },

    getNextActiveKey (next) {
      const activeKey = this.$data._activeKey
      const children = []
      this.$props.children.forEach((c) => {
        if (c && !c.disabled && c.disabled !== '') {
          if (next) {
            children.push(c)
          } else {
            children.unshift(c)
          }
        }
      })
      const length = children.length
      let ret = length && children[0].key
      children.forEach((child, i) => {
        if (child.key === activeKey) {
          if (i === length - 1) {
            ret = children[0].key
          } else {
            ret = children[i + 1].key
          }
        }
      })
      return ret
    },
  },
  render () {
    const props = this.$props
    const {
      prefixCls,
      navWrapper,
      tabBarPosition,
      renderTabContent,
      renderTabBar,
      destroyInactiveTabPane,
    } = props
    const cls = {
      [prefixCls]: 1,
      [`${prefixCls}-${tabBarPosition}`]: 1,
    }

    this.tabBar = renderTabBar()
    const contents = [
      cloneElement(this.tabBar, {
        props: {
          prefixCls,
          navWrapper,
          tabBarPosition,
          panels: props.children,
          activeKey: this.$data._activeKey,
        },
        on: {
          keydown: this.onNavKeyDown,
          tabClick: this.onTabClick,
        },
        key: 'tabBar',
      }),
      cloneElement(renderTabContent(), {
        props: {
          prefixCls,
          tabBarPosition,
          activeKey: this.$data._activeKey,
          destroyInactiveTabPane,
        },
        on: {
          change: this.setActiveKey,
        },
        children: props.children,
        key: 'tabContent',
      }),
    ]
    if (tabBarPosition === 'bottom') {
      contents.reverse()
    }
    return (
      <div {...{ on: omit(this.$listeners, ['change']), class: cls }}>
        {contents}
      </div>
    )
  },
}
